﻿
// MFCGCView.cpp: CMFCGCView 类的实现
//
#include "pch.h"
#include "framework.h"
// SHARED_HANDLERS 可以在实现预览、缩略图和搜索筛选器句柄的
// ATL 项目中进行定义，并允许与该项目共享文档代码。
#ifndef SHARED_HANDLERS
#include "MFCGC.h"
#endif

#include "MFCGCDoc.h"
#include "MFCGCView.h"
#include "CPoint3D.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
#include "MainFrm.h"
#include "CLine.h"
#define ROUND(a) int(a+0.5)//四舍五入
#define PI 3.1415926//圆周率
// CMFCGCView

IMPLEMENT_DYNCREATE(CMFCGCView, CView)

BEGIN_MESSAGE_MAP(CMFCGCView, CView)
	// 标准打印命令
	ON_COMMAND(ID_FILE_PRINT, &CView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_DIRECT, &CView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CView::OnFilePrintPreview)
	ON_WM_LBUTTONUP()
	ON_WM_RBUTTONUP()
	ON_WM_KEYDOWN()
END_MESSAGE_MAP()

// CMFCGCView 构造/析构

CMFCGCView::CMFCGCView() noexcept
{
	// TODO: 在此处添加构造代码

}

CMFCGCView::~CMFCGCView()
{
}


void CMFCGCView::ReadPoint()//点表
{
	double a = 400;//立方体边长
	//顶点的三维坐标(x,y,z)
	P[0].x = -a / 2; P[0].y = -a / 2; P[0].z = -a / 2;
	P[1].x = a / 2; P[1].y = -a / 2; P[1].z = -a / 2;
	P[2].x = a / 2; P[2].y = a / 2; P[2].z = -a / 2;
	P[3].x = -a / 2; P[3].y = a / 2; P[3].z = -a / 2;
	P[4].x = -a / 2; P[4].y = -a / 2; P[4].z = a / 2;
	P[5].x = a / 2; P[5].y = -a / 2; P[5].z = a / 2;
	P[6].x = a / 2; P[6].y = a / 2; P[6].z = a / 2;
	P[7].x = -a / 2; P[7].y = a / 2; P[7].z = a / 2;
}
void CMFCGCView::ReadEdge()//边表
{
	E[0].p[0] = 0; E[0].p[1] = 1;
	E[1].p[0] = 1; E[1].p[1] = 2;
	E[2].p[0] = 2; E[2].p[1] = 3;
	E[3].p[0] = 3; E[3].p[1] = 0;
	E[4].p[0] = 4; E[4].p[1] = 5;
	E[5].p[0] = 5; E[5].p[1] = 6;
	E[6].p[0] = 6; E[6].p[1] = 7;
	E[7].p[0] = 7; E[7].p[1] = 4;
	E[8].p[0] = 0; E[8].p[1] = 4;
	E[9].p[0] = 5; E[9].p[1] = 1;
	E[10].p[0] = 2; E[10].p[1] = 6;
	E[11].p[0] = 7; E[11].p[1] = 3;
}
void CMFCGCView::ReadFace()//面表
{
	F[0].e[0] = 0; F[0].e[1] = 3; F[0].e[2] = 2; F[0].e[3] = 1;//后面
	F[1].e[0] = 4; F[1].e[1] = 5; F[1].e[2] = 6; F[1].e[3] = 7;//前面
	F[2].e[0] = 0; F[2].e[1] = 4; F[2].e[2] = 7; F[2].e[3] = 3;//左面
	F[3].e[0] = 1; F[3].e[1] = 2; F[3].e[2] = 6; F[3].e[3] = 5;//右面
	F[4].e[0] = 3; F[4].e[1] = 7; F[4].e[2] = 6; F[4].e[3] = 2;//顶面
	F[5].e[0] = 0; F[5].e[1] = 1; F[5].e[2] = 5; F[5].e[3] = 4;//底面
}
void CMFCGCView::InitParameter()//透视变换参数初始化
{
	k[1] = sin(PI * Theta / 180);
	k[2] = sin(PI * Phi / 180);
	k[3] = cos(PI * Theta / 180);
	k[4] = cos(PI * Phi / 180);
	k[5] = k[3] * k[2];
	k[6] = k[1] * k[2];
	k[7] = k[3] * k[4];
	k[8] = k[1] * k[4];
	ViewPoint.x = R * k[5];//用户坐标系的视点球坐标
	ViewPoint.y = R * k[6];
	ViewPoint.z = R * k[4];
}
void CMFCGCView::PerProject(CP3 P)//透视变换
{
	CP3 ViewP;
	ViewP.x = -k[1] * P.x + k[3] * P.y;//观察坐标系三维坐标
	ViewP.y = -k[7] * P.x - k[8] * P.y + k[2] * P.z;
	ViewP.z = -k[5] * P.x - k[6] * P.y - k[4] * P.z + R;
	ScreenP.x = d * ViewP.x / ViewP.z;//屏幕坐标系二维坐标
	ScreenP.y = ROUND(d * ViewP.y / ViewP.z);
}
void CMFCGCView::DoubleBuffer()//双缓冲
{
	CRect Rect;
	GetClientRect(&Rect);
	CDC* pDC = GetDC();
	pDC->SetMapMode(MM_ANISOTROPIC);//自定义坐标系
	pDC->SetWindowExt(Rect.Width(), Rect.Height());
	pDC->SetViewportExt(Rect.Width(), -Rect.Height());//x轴水平向右，y轴垂直向上
	pDC->SetViewportOrg(Rect.right / 2, Rect.bottom / 2);//屏幕中心为原点	
	CDC	MemDC, Picture;
	MemDC.CreateCompatibleDC(pDC);
	MemDC.SetMapMode(MM_ANISOTROPIC);
	MemDC.SetWindowExt(Rect.Width(), Rect.Height());
	MemDC.SetViewportExt(Rect.right, -Rect.bottom);
	MemDC.SetViewportOrg(Rect.right / 2, Rect.bottom / 2);
	MemDC.BitBlt(-Rect.right / 2, -Rect.bottom / 2, Rect.Width(), Rect.Height(), &Picture, -Rect.right / 2, -Rect.bottom / 2, SRCCOPY);
	for (int nFace = 0; nFace < 6; nFace++)
	{
		CVector VecViewPoint(ViewPoint);
		CVector VP1(P[E[F[nFace].e[0]].p[0]]);//面的第一个顶点矢量
		CVector VP2(P[E[F[nFace].e[1]].p[0]]);//面的第二个顶点矢量
		CVector VP3(P[E[F[nFace].e[2]].p[0]]);//面的第三个顶点矢量
		VS = VecViewPoint - VP1;//面的视矢量
		CVector VP2P1 = VP2 - VP1;//面的一个边矢量
		CVector VP3P2 = VP3 - VP2;//面的另一个边矢量				
		VN = VP2P1 * VP3P2;//面的法矢量	
		if (Dot(VS, VN) >= 0)//判断数量积正负
			Draw7_1(&MemDC, nFace);//数量积大于零，表面画出
	}
	pDC->BitBlt(-Rect.right / 2, -Rect.bottom / 2, Rect.right, Rect.bottom, &MemDC, -Rect.right / 2, -Rect.bottom / 2, SRCCOPY);
	ReleaseDC(pDC);
}
void CMFCGCView::Draw7_1(CDC* pDC, int nface)//绘制四边形
{
	CP2 t;
	for (int nEdge = 0; nEdge < 4; nEdge++)//边循环
	{
		PerProject(P[E[F[nface].e[nEdge]].p[0]]);//透视投影
		if (nEdge == 0)
		{
			pDC->MoveTo(ROUND(ScreenP.x), ROUND(ScreenP.y));
			t = ScreenP;
		}
		else
		{
			pDC->LineTo(ROUND(ScreenP.x), ROUND(ScreenP.y));
		}
	}
	pDC->LineTo(ROUND(t.x), ROUND(t.y));//闭合四边形

}



void CMFCGCView::exercises7_1(CDC* pDC)
{
	if (first_71)
	{
		R = 1000.0; d = 800; Theta = 0; Phi = -90;
		ReadPoint();
		ReadEdge();
		ReadFace();
	}
	InitParameter();
	for (int nFace = 0; nFace < 6; nFace++)
	{
		CVector VecViewPoint(ViewPoint);
		CVector VP1(P[E[F[nFace].e[0]].p[0]]);//面的第一个顶点矢量
		CVector VP2(P[E[F[nFace].e[1]].p[0]]);//面的第二个顶点矢量
		CVector VP3(P[E[F[nFace].e[2]].p[0]]);//面的第三个顶点矢量
		VS = VecViewPoint - VP1;//面的视矢量
		CVector VP2P1 = VP2 - VP1;//面的一个边矢量
		CVector VP3P2 = VP3 - VP2;//面的另一个边矢量				
		VN = VP2P1 * VP3P2;//面的法矢量	
		if (Dot(VS, VN) >= 0)//判断数量积正负
			Draw7_1(pDC, nFace);//数量积大于零，表面画出
	}
	first_71 = false;
}
void exercises7_2(CDC* pDC)
{




}

void exercises7_3(CDC* pDC)
{




}



void DrawGouraudTriangle(CDC* pDC, COLORREF CA, COLORREF CB, COLORREF CC, CPoint P[], int(&MAT)[400][400], int page)
{
	int MaxX = max(P[2].x, max(P[0].x, P[1].x));
	COLORREF BackgroundColor = RGB(255, 255, 255); // 背景色
	COLORREF CA1, CB1, CC1;
	// 分离颜色分量
	auto GetR = [](COLORREF color) { return GetRValue(color); };
	auto GetG = [](COLORREF color) { return GetGValue(color); };
	auto GetB = [](COLORREF color) { return GetBValue(color); };

	// 插值函数
	auto Interpolate = [](double c1, double c2, double t) {
		return c1 + (c2 - c1) * t;
		};

	for (int i = 0; i < 3; i++) // 循环三角形的每条边
	{
		int j = (i + 1) % 3;  // 下一顶点
		int f = (i + 2) % 3;  // 剩余顶点

		double slopeInverse = double(P[i].x - P[j].x) / double(P[i].y - P[j].y); // 斜率倒数

		// 确定 y 范围和起始 x 值
		int yMin = min(P[i].y, P[j].y);
		int yMax = max(P[i].y, P[j].y);
		CA1 = CA, CB1 = CB, CC1 = CC; //颜色备份
		if (P[i].y != yMax) {
			//如果点的顺序交换 匹配的颜色顺序也交换 最后再恢复
			CA = CB1;
			CB = CA1;
		}

		double startX = (P[i].y == yMin) ? P[i].x : P[j].x;

		for (int y = yMin; y < yMax; y++) // 遍历扫描线
		{
			// 计算交点颜色插值
			double t1 = (y - yMin) / double(yMax - yMin);
			COLORREF Cd = RGB(
				Interpolate(GetR(CA), GetR(CC), t1),
				Interpolate(GetG(CA), GetG(CC), t1),
				Interpolate(GetB(CA), GetB(CC), t1));

			double t2 = (y - yMin) / double(P[f].y - yMin);
			COLORREF Ce = RGB(
				Interpolate(GetR(CB), GetR(CC), t2),
				Interpolate(GetG(CB), GetG(CC), t2),
				Interpolate(GetB(CB), GetB(CC), t2));

			int xLeft = int(startX);
			int xRight = MaxX;

			for (int x = xLeft; x <= xRight; x++) // 遍历扫描线上的每个像素
			{
				double t = (x - xLeft) / double(xRight - xLeft);
				COLORREF Cf = RGB(
					Interpolate(GetR(Cd), GetR(Ce), t),
					Interpolate(GetG(Cd), GetG(Ce), t),
					Interpolate(GetB(Cd), GetB(Ce), t));

				int p = MAT[x ][y + 200]; // 判断是否已处理
				if (!p)
				{
					p = page;
					MAT[x ][y + 200] = page; // 标记为已处理
				}

				if (BackgroundColor != pDC->GetPixel(x, y) && (p == page))
				{
					pDC->SetPixelV(x, y, BackgroundColor); // 涂背景色
					MAT[x ][y + 200] = 0;
					continue;
				}
				if (BackgroundColor == pDC->GetPixel(x, y) && (p == page)) // 涂当前颜色
				{
					pDC->SetPixelV(x, y, Cf);
				}
			}
			startX += slopeInverse; // 更新 x 起点
		}
		CA = CA1; CB = CB1; CC = CC1;
	}
}



//渐变颜色的三角形填充 8-3
void FillPolygonWithColor(CDC* pDC, COLORREF CA, COLORREF CB, COLORREF CC,CPoint P[], int(&MAT)[400][400],int page)
{
	int MaxX =max(P[2].x,max(P[0].x, P[1].x));
	//C0 起始颜色 C1结束颜色
	COLORREF BClr = RGB(255, 255, 255);//背景色
	COLORREF Cd, Ce, Cf;
	int yMin, yMax;//边的最小y值与最大y值
	int yA, yB, yC,yD,yE,yF; //第1 2 3个点
	int xd,xe, xf;//f e 的x
	double x, y, k;//x,y当前点，k斜率的倒数
	for (int i = 0; i < 3; i++)//循环三角形所有边
	{
		int j = (i + 1) % 3;//第二个点
		int f = (i + 2) % 3; //第三个点
		k = double(P[i].x - P[j].x) / double(P[i].y - P[j].y);//计算1/k
		if (P[i].y < P[j].y)//得到每条边y的最大值与最小值
		{
			yMin = P[i].y;
			yMax = P[j].y;
			x = P[i].x;//得到x|ymin
		}
		else
		{
			yMin = (P[j].y);
			yMax = P[i].y;
			x = P[j].x;
		}
		
		xd = P[i].x < P[j].x ? P[i].x : P[j].x; //xmin
		xe = P[i].x > P[j].x ? P[i].x : P[j].x;
		yA = yMax;
		yC = yMin; 
		yB = P[f].y;
		int flag = k >= 0 ? 1 : -1;
		for (yD = yE = yF = yMin; yD< yMax; yD++)//沿每一条边循环扫描线
		{
			Cd = CA * ((yD - yC) / double(yA - yC)) + CC * ((yA - yD) / double(yA - yC));
			Ce = CB * ((yE - yC) / double(yB - yC)) + CC * ((yB - yE) / double(yB - yC));
			//对每一条扫描线与边的交点的右侧像素循环   
			for (int xf = x; xf < MaxX; xf++)
				//MaxX为包围盒的右边界
			{
				Cf =( Cd * ((xf - xe) / double(xd - xe)) + Ce * ((xd - xf) / double(xd - xe)));

				int p = MAT[xf+200][yD+200];//记录第几次修改的
				if (!p){
					p = page;
					MAT[xf+200][yD+200] = page;  //未被修改则标记为本次"
				}

				if (RGB(255, 255, 255) != pDC->GetPixel(xf, yD) && (p == page))
				{
					pDC->SetPixelV(xf, yD, RGB(255,255,255)); //如果是本次修改的则取补色
					MAT[xf + 200][yD + 200] = 0;
					continue;
				}
				if (RGB(255, 255, 255) == pDC->GetPixel(xf, yD) && (p == page)) //如果是本次修改 但尚未涂色 则涂色
					pDC->SetPixelV(xf, yD, Cf);
				
			}
			
			x += k;
		}
	}
}

//习题8-3的函绘图函数
void exercises8_3(CDC* pDC) {
	COLORREF C[6] = {
		RGB(255,0,0),
		RGB(255,255,0),
		RGB(0,255,0),
		RGB(0,255,255),
		RGB(0,0,255),
		RGB(255,0,255)
	};
	// 创建六个点
	const int radius = 200;  // 半径为 200
	CPoint points[6];
	// 计算六个顶点的坐标
	for (int i = 0; i < 6; ++i) {
		double angle = i * 60.0 * 3.14159 / 180.0;
		points[i] = CPoint(static_cast<int>(radius * cos(angle)) - 300,
			static_cast<int>(radius * sin(angle)));
	}
	for (size_t i = 0; i < 6; i++)
	{
		pDC->MoveTo(CPoint(-300, 0));
		pDC->LineTo(points[i % 6]);
		pDC->LineTo(points[(i + 1) % 6]);
		pDC->LineTo(CPoint(-300, 0));
		CBrush brush(C[i]);
		CBrush* pOldBrush = pDC->SelectObject(&brush);
		CPoint P3[3] = { CPoint(-300,0), points[i % 6] ,points[(i + 1) % 6] };
		// 使用 Polygon 方法填充三角形
		pDC->Polygon(P3, 3);
		// 恢复旧画刷
		pDC->SelectObject(pOldBrush);

	}
	// 计算六个顶点的坐标
	for (int i = 0; i < 6; ++i) {
		double angle = i * 60.0 * 3.14159 / 180.0; 
		points[i] = CPoint(static_cast<int>(radius * cos(angle))+ 200,
		static_cast<int>(radius * sin(angle)));
	}

	int CMAT[400][400] = { 0 };
	for (size_t i = 0; i < 6; i++)
	{
		pDC->MoveTo(CPoint(200, 0));
		pDC->LineTo(points[i % 6]);
		pDC->LineTo(points[(i + 1) % 6]);
		pDC->LineTo(CPoint(200, 0));
		// 定义三角形的顶点
		CPoint P3[3] = {CPoint(200,0), points[i % 6] ,points[(i+1) % 6]  };
		DrawGouraudTriangle(pDC, RGB(255,255,255), C[(i - 1) %6], C[(i)%6], P3, CMAT, i + 1);

	}



}


//习题8-5的函绘图函数
void exercises8_5(CDC* pDC) {

}



BOOL CMFCGCView::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: 在此处通过修改
	//  CREATESTRUCT cs 来修改窗口类或样式

	return CView::PreCreateWindow(cs);
}
//由四个点得交点 整型
CPoint intersection_point(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
{
	double A1, B1, C1, A2, B2, C2, denominator;
	double x, y;
	A1 = y2 - y1;
	B1 = x1 - x2;
	C1 = A1 * x1 + B1 * y1;

	A2 = y4 - y3;
	B2 = x3 - x4;
	C2 = A2 * x3 + B2 * y3;

	denominator = A1 * B2 - A2 * B1;
	if (denominator == 0) {
		return NULL;
	}

	x = (B2 * C1 - B1 * C2) / denominator;
	y = (A1 * C2 - A2 * C1) / denominator;
	return CPoint(round(x), round(y));
}
#include <queue>

void CMFCGCView::SeedFill(CDC* pDC, int x, int y, COLORREF fillColor, COLORREF boundaryColor)
{
	// 获取种子点的初始颜色
	COLORREF startColor = pDC->GetPixel(x, y);

	// 如果种子点已经是填充颜色或者是边界颜色，则不进行填充
	if (startColor == fillColor || startColor == boundaryColor)
		return;

	// 使用队列来存储需要填充的像素位置
	std::queue<CPoint> pixelQueue;
	pixelQueue.push(CPoint(x, y));

	// 8连通方向（上下左右以及四个对角线方向）
	int dx[8] = { -1, 1, 0, 0, -1, -1, 1, 1 };
	int dy[8] = { 0, 0, -1, 1, -1, 1, -1, 1 };

	while (!pixelQueue.empty())
	{
		// 从队列中取出一个点
		CPoint point = pixelQueue.front();
		pixelQueue.pop();

		// 获取当前点的颜色
		COLORREF currentColor = pDC->GetPixel(point.x, point.y);

		// 如果当前点是起始颜色，则填充它并处理它的相邻点
		if (currentColor == startColor)
		{
			// 填充当前像素
			pDC->SetPixel(point.x, point.y, fillColor);

			// 检查8个方向上的相邻像素
			for (int i = 0; i < 8; ++i)
			{
				int newX = point.x + dx[i];
				int newY = point.y + dy[i];

				// 获取相邻像素的颜色
				COLORREF neighborColor = pDC->GetPixel(newX, newY);

				// 如果相邻像素的颜色不是边界颜色且不是填充颜色，则将它加入队列
				if (neighborColor != fillColor && neighborColor != boundaryColor)
				{
					pixelQueue.push(CPoint(newX, newY));
				}
			}
		}
	}
}
// CMFCGCView 绘图
#include <cmath>
using namespace std;
void DrawEdges(CDC* pDC, CPoint projected[]) {
	// 绘制长方体的边和尖顶
	int edges[15][2] = {
		// 底面四条边
		{0, 1}, {1, 2}, {2, 3}, {3, 0},  // 四条底面边，形成一个矩形

		// 顶面四条边
		{4, 8}, {7, 8}, {5, 9}, {6,9},{8,9} , // 5条顶

		// 侧面四条边（连接上下两层）
		{0, 4}, {1, 5}, {2, 6}, {3, 7} ,{4,5},{6,7}  // 连接底部和顶部的四条侧面边
	};

	for (int i = 0; i < 15; i++) {
		pDC->MoveTo(projected[edges[i][0]]);
		pDC->LineTo(projected[edges[i][1]]);
	}
}
CPoint ProjectFrontView(CPoint3D pt, CPoint translation) {
	return CPoint((int)pt.x + translation.x, (int)pt.y + translation.y);
}

CPoint ProjectSideView(CPoint3D pt, CPoint translation) {
	return CPoint((int)pt.z + translation.x, (int)pt.y + translation.y);
}

CPoint ProjectTopView(CPoint3D pt, CPoint translation) {
	return CPoint((int)pt.x + translation.x, (int)pt.z + translation.y);
}

void DrawFrontView(CDC* pDC, CPoint3D vertices[], CPoint translation) {
	CPoint projected[10];
	for (int i = 0; i < 10; i++) {
		projected[i] = ProjectFrontView(vertices[i], translation);
	}
	DrawEdges(pDC, projected);
}
void DrawSideView(CDC* pDC, CPoint3D vertices[], CPoint translation) {
	CPoint projected[10];
	for (int i = 0; i < 10; i++) {
		projected[i] = ProjectSideView(vertices[i], translation);
	}
	DrawEdges(pDC, projected);
}
void DrawTopView(CDC* pDC, CPoint3D vertices[], CPoint translation) {
	CPoint projected[10];
	for (int i = 0; i < 10; i++) {
		projected[i] = ProjectTopView(vertices[i], translation);
	}
	DrawEdges(pDC, projected);
}
CPoint ProjectOblique(CPoint3D pt, double angle = 45, double scale = 0.5) {
	double theta = angle * 3.14159 / 180.0; // 角度转换为弧度
	double x = pt.x + scale * pt.z * cos(theta);
	double y = pt.y + scale * pt.z * sin(theta);
	return CPoint((int)x, (int)y);
}

void Draw3DObject(CDC* pDC, CPoint3D vertices[], CPoint position, double angle, double scale) {
	// 计算投影点并添加位置偏移
	CPoint projected[10];
	for (int i = 0; i < 10; i++) {
		projected[i] = ProjectOblique(vertices[i], angle, scale);
		projected[i].x += position.x;
		projected[i].y += position.y;
	}

	// 绘制长方体的边和尖顶
	int edges[15][2] = {
		// 底面四条边
		{0, 1}, {1, 2}, {2, 3}, {3, 0},  // 四条底面边，形成一个矩形

		// 顶面四条边
		{4, 8}, {7, 8}, {5, 9}, {6,9},{8,9} , // 5条顶

		// 侧面四条边（连接上下两层）
		{0, 4}, {1, 5}, {2, 6}, {3, 7} ,{4,5},{6,7}  // 连接底部和顶部的四条侧面边
	};

	for (int i = 0; i < 15; i++) {
		pDC->MoveTo(projected[edges[i][0]]);
		pDC->LineTo(projected[edges[i][1]]);
	}
}

void CMFCGCView::FillPolygon(CDC* pDC, COLORREF GetClr, CPoint P[], int MaxX)
{
	COLORREF BClr = RGB(255, 255, 255);//背景色
	COLORREF FClr = GetClr;//填充色
	int yMin, yMax;//边的最小y值与最大y值
	double x, y, k;//x,y当前点，k斜率的倒数
	for (int i = 0; i < 7; i++)//循环多边形所有边
	{
		int j = (i + 1) % 7;
		k = double(P[i].x - P[j].x) / double(P[i].y - P[j].y);//计算1/k
		if (P[i].y < P[j].y)//得到每条边y的最大值与最小值
		{
			yMin = P[i].y;
			yMax =P[j].y;
			x = P[i].x;//得到x|ymin
		}
		else
		{
			yMin = (P[j].y);
			yMax =P[i].y;
			x = P[j].x;
		}

		for (y = yMin; y < yMax; y++)//沿每一条边循环扫描线
		{
			//对每一条扫描线与边的交点的右侧像素循环   
			for (int m = x; m < MaxX; m++)
				//MaxX为包围盒的右边界
			{
				if (FClr == pDC->GetPixel(m, y))		
					pDC->SetPixelV(m, y, BClr);
				else
					pDC->SetPixelV(m,y, FClr);
			}
			x += k;
		}
	}
}

//CPoint ProjectOblique(CPoint3D pt, double angle, double scale) {
//	// 设置投影矩阵
//	double theta = angle * 3.14159 / 180.0; // 角度转换为弧度
//	double x = pt.x + scale * pt.z * cos(theta);
//	double y = pt.y + scale * pt.z * sin(theta);
//	return CPoint((int)x, (int)y);
//}


void DrawCube(CDC* pDC, CPoint3D vertices[], double angle, double scale, CPoint position) {
	// 投影顶点并添加位置偏移
	CPoint projected[8];
	for (int i = 0; i < 8; i++) {
		projected[i] = ProjectOblique(vertices[i], angle, scale);
		projected[i].x += position.x;
		projected[i].y += position.y;
	}

	// 定义立方体的边
	int edges[12][2] = {
		{0, 1}, {1, 2}, {2, 3}, {3, 0},
		{4, 5}, {5, 6}, {6, 7}, {7, 4},
		{0, 4}, {1, 5}, {2, 6}, {3, 7}
	};

	// 绘制立方体的边
	for (int i = 0; i < 12; i++) {
		pDC->MoveTo(projected[edges[i][0]]);
		pDC->LineTo(projected[edges[i][1]]);
	}
}


void CMFCGCView::OnDraw(CDC* pDC)
{
	CMFCGCDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;
	// 获取主框架窗口
	CMainFrame* pMainFrame = (CMainFrame*)GetParentFrame();
	CRect rect;//不是单纯的一个数值
	GetClientRect(rect);
	if (pMainFrame->nowDraw != 56) {
		//习题56不进行视区调整
		//将所有的视区都修改为向上向右为正 原点为中间
		
		pDC->SetMapMode(MM_ANISOTROPIC);//变量是一种映射模式；->：指向成员运算符
		pDC->SetWindowExt(rect.Width(), rect.Height());//设置窗口大小（宽度、高度）
		pDC->SetViewportExt(rect.Width(), -rect.Height());//设置视区的大小，使Y轴向上
		pDC->SetViewportOrg(rect.Width() / 2, rect.Height() / 2);//设置原点位置
		rect.OffsetRect(-rect.Width() / 2, -rect.Height() / 2);//偏移函数,向左偏移

	}
	
	if (pMainFrame)
	{
		// 访问 CMainFrame 中的变量
		int nowDraw = pMainFrame->nowDraw;
		CString txt;
		txt.Format(_T("%d"), nowDraw);

		// 获取主窗口的尺寸
		CRect clientRect;
		GetClientRect(&clientRect);

		// 计算窗口中心
		int centerX = clientRect.Width() / 2;
		int centerY = clientRect.Height() / 2;

		// 根据nowDraw 进行绘图
		//pDC->TextOut(10, 10, CString("Value: ")+ txt);
		switch (nowDraw)
		{
		case 24:
		{
			pDC->TextOut(10, 10, CString("习题2-4: "));
			break;
		}
		case 25:

		{
			int depth=pMainFrame->dep;
			pDC->TextOut(10- centerX, centerY, CString("习题2-5: "));

			CPen pen(PS_SOLID, 1, RGB(0, 0, 0)); // 黑色边框
			CPen* pOldPen = pDC->SelectObject(&pen);
			pDC->SelectStockObject(NULL_BRUSH);


			CPoint pList[5];
			double c=0.5*3.1415926,r=200;
			double x, y;
			//迭代深度
			for (size_t j = 0; j < depth; j++)
			{
				//根据起始弧度和半径计算顶点
				for (size_t i = 0; i < 5; i++)
				{
					x =(r * cos(c));
					y = (r * sin(c));
					pList[i] = CPoint(round(x), round(y));
					c += 0.4 * 3.1415926;
				}
				//绘制
				CPoint p, p2;
				for (size_t i = 0; i < 5; i++)
				{
					
					p = pList[i];
					for (size_t m= 0; m< 5; m++)
					{
						pDC->MoveTo(p);
						p2 = pList[m];
						pDC->LineTo(p2);
					}
					
				}
				
				//计算下层迭代的起始位置 转为起始弧度和半径
				CPoint pp=intersection_point(
					pList[0].x, pList[0].y, pList[2].x, pList[2].y,
					pList[1].x, pList[1].y, pList[3].x, pList[3].y);

				r = pow((pow(pp.x, 2) + pow(pp.y, 2)), 0.5);
				c = asin(pp.y / r);
			}
			
			pDC->SelectObject(pOldPen);
			break;
		}
		case 33:
		{
			//习题3-3
			pDC->TextOut(10 - centerX, centerY, CString("习题3-3: "));
	
			CLine e;
			CPoint p1, p2;

			//根据线条数量画图
			for (size_t i = 0; i < LineNum; i++)
			{
				p1 = lineList[i][0];
				p2 = lineList[i][1];
				e.MoveTo(pDC, p1.x- rect.Width() / 2, -p1.y+rect.Height() / 2);
				e.LineTo(pDC, p2.x - rect.Width() / 2, -p2.y + rect.Height() / 2);
			}
			
			break;
		}

		case 34:
		{//习题3-4
			CPoint x3_5p1 = pMainFrame->x3_5p1;
			CPoint x3_5p2 = pMainFrame->x3_5p2;
			pDC->TextOut(10 - centerX, centerY, CString("习题3-4: "));
			wuLine(pDC, x3_5p1, x3_5p2);
			break;
		}
		case 38: {
			pDC->TextOut(10 - centerX, centerY, CString("习题3-8: "));
			
			CLine e;
			e.MoveTo(pDC, pMainFrame->x3_8p1.x, pMainFrame->x3_8p1.y);
			e.LineToColor(pDC, pMainFrame->x3_8p2.x, pMainFrame->x3_8p2.y, pMainFrame->x3_8C1, pMainFrame->x3_8C2);

			break;
		}
		case 39:
		{
			pDC->TextOut(10 - centerX, centerY, CString("习题3-9: "));

			break;
		}
		case 43:
		{
			pDC->TextOut(10 - centerX, centerY, CString("习题4-3: "));
			CRect rectLeft(-250, 200, -50, 0);  // 左边的正方形
			CRect rectRight(50, 200, 250, 0); // 右边的正方形

			    // 创建四种不同颜色的刷子来填充四个三角形
			CBrush brush1(RGB(0, 0, 0));    // 黑色刷子
		
			// 定义左边正方形的四个顶点
			POINT leftTopLeft = { rectLeft.left, rectLeft.top };        // 左上角
			POINT leftTopRight = { rectLeft.right, rectLeft.top };      // 右上角
			POINT leftBottomLeft = { rectLeft.left, rectLeft.bottom };  // 左下角
			POINT leftBottomRight = { rectLeft.right, rectLeft.bottom }; // 右下角
		
			// 定义右边正方形的四个顶点
			POINT rightTopLeft = { rectRight.left, rectRight.top };        // 左上角
			POINT rightTopRight = { rectRight.right, rectRight.top };      // 右上角
			POINT rightBottomLeft = { rectRight.left, rectRight.bottom };  // 左下角
			POINT rightBottomRight = { rectRight.right, rectRight.bottom }; // 右下角
			
			// 左边正方形的2个三角形
			POINT leftTriangle1[] = { leftTopLeft, leftTopRight, leftBottomLeft };
			POINT leftTriangle2[] = { leftTopRight, leftBottomRight, leftBottomLeft };
	
			// 右边正方形的2个三角形
			POINT rightTriangle1[] = { rightTopLeft, rightBottomLeft, rightBottomRight };
			POINT rightTriangle2[] = { rightTopLeft, rightTopRight, rightBottomRight };

			// 绘制左正方形的右对角线
			pDC->MoveTo(leftTopRight);
			pDC->LineTo(leftBottomLeft);

			// 绘制右正方形的左对角线
			pDC->MoveTo(rightTopLeft);
			pDC->LineTo(rightBottomRight);

			// 填充左正方形的四个三角形
			pDC->SelectObject(&brush1);
			pDC->Polygon(leftTriangle1, 3);  // 左上角三角形
			pDC->SelectObject(&brush1);
			pDC->Polygon(leftTriangle2, 3);  // 右上角三角形
			pDC->SelectObject(&brush1);

			// 填充右正方形的四个三角形
			pDC->SelectObject(&brush1);
			pDC->Polygon(rightTriangle1, 3);  // 左上角三角形
			pDC->SelectObject(&brush1);
			pDC->Polygon(rightTriangle2, 3);  // 右上角三角形
	
			break;
		}
		case 47:
		{
			pDC->TextOut(10 - centerX, centerY, CString("习题4-7: "));
			CRect rect(-220, 220 ,220, -220);
			CPoint pList[7] = 
			{
				CPoint(7,8),CPoint(3,12),CPoint(1,7),CPoint(3,1),
				CPoint(6,5),CPoint(8,1),CPoint(12,9),
			};
			//放大40倍 坐标转换
			for (size_t i = 0; i < 7; i++)
			{
				pList[i].x *= 40;
				pList[i].y *= 40;
				pList[i].x -= 260;
				pList[i].y -= 260;
			}
			pDC->Rectangle(rect);
			for (size_t i = 0; i < 7; i++)
			{
				pDC->MoveTo(pList[i]);
				pDC->LineTo(pList[(i + 1)%7]);
			}
			FillPolygon(pDC,RGB(0,0,0),pList,220);
			break;
		}
		case 49:
		{
			pDC->TextOut(10 - centerX, centerY, CString("习题4-9: "));
			// 设置边界矩形
			CRect rect1(-200, 0, 0, -200);
			CRect rect2(0, 200, 200, 0);
			// 创建一个画笔用于绘制矩形边界
			CPen pen(PS_SOLID, 1, RGB(0, 0, 0));  // 黑色画笔
			pDC->SelectObject(&pen);
			// 定义填充颜色和边界颜色
			COLORREF fillColor = RGB(0, 0, 0);   // 黑色填充
			COLORREF boundaryColor = RGB(0, 0, 0); // 黑色边界

			pDC->Rectangle(rect1);
			pDC->Rectangle(rect2);
			// 选定种子点
			int seedX1 = -100;
			int seedY1 = -100;
			int seedX2 = 100;
			int seedY2 = 100;
			// 调用种子填充算法
			SeedFill(pDC, seedX1, seedY1, fillColor, boundaryColor);
			SeedFill(pDC, seedX2, seedY2, fillColor, boundaryColor);
			break;
		}
		case 53:
		{
			
			pDC->TextOut(10 - centerX, centerY, CString("习题5-3: "));
			CPen pen(PS_SOLID, 1, RGB(0, 0, 0));  
			pDC->SelectObject(&pen);
			int a=150;
			CRect rect{-a/2,-150,a/2,-150-a};
			pDC->TextOutW(0, 0, L"O");
			pDC->MoveTo(-150, 0);
			pDC->LineTo(150, 0);
			pDC->MoveTo(0, 0);
			CPoint center(0, -150 - a / 2);
			// 正方形初始顶点
			CPoint points[4] = {
				{ rect.left, rect.top },
				{ rect.right, rect.top },
				{ rect.right, rect.bottom },
				{ rect.left, rect.bottom }
			};
			pDC->MoveTo(0, 0);
			pDC->LineTo(0, -150 - a / 2);
			//旋转
			if (pMainFrame->rolate5_3&& this->nowAngle<2* 3.14159)
			{
				double totalAngle = 2 * 3.14159 ;  
				float angle = this->nowAngle;

				// 计算顶点
				for (int i = 0; i < 4; i++)
				{
					int x = points[i].x - center.x;
					int y = points[i].y - center.y;
					points[i].x = center.x + static_cast<int>(x * cos(angle) - y * sin(angle));
					points[i].y = center.y + static_cast<int>(x * sin(angle) + y * cos(angle));
						
				}
				pDC->MoveTo(points[3]);
				// 绘制
				for (int i = 0; i < 4; i++)
				{
					pDC->LineTo(points[i]);
				}
				this->nowAngle+=totalAngle /100;
				Sleep(50);
				this->Invalidate();
			}
			else
			{
				float angle = this->nowAngle;

				// 计算顶点
				for (int i = 0; i < 4; i++)
				{
					int x = points[i].x - center.x;
					int y = points[i].y - center.y;
					points[i].x = center.x + static_cast<int>(x * cos(angle) - y * sin(angle));
					points[i].y = center.y + static_cast<int>(x * sin(angle) + y * cos(angle));

				}
				pDC->MoveTo(points[3]);
				// 绘制
				for (int i = 0; i < 4; i++)
				{
					pDC->LineTo(points[i]);
				}
			}
			pDC->MoveTo(0, 0);
			pDC->LineTo(0, -150 - a / 2);
			break;
		}
		case 56:
		{
			pDC->TextOut(0, 10, CString("习题5-6: "));
			CRect clientRect;
			GetClientRect(&clientRect);
			
			// 左侧和右侧区域的划分
			int midX = clientRect.Width() / 2;
			CRect leftRect(clientRect.left+50, clientRect.top+100, midX-50, clientRect.bottom-100);
			CRect rightRect(midX+50, clientRect.top+150, clientRect.right-50, clientRect.bottom-150);
			// 定义窗口坐标和视区坐标（左侧区域中间是窗口，右侧区域是视区）
			CRect windowRect= leftRect; // 窗口坐标系
			CRect viewportRect(rightRect.left , rightRect.top , rightRect.right, rightRect.bottom ); // 视区

			// 绘制左右区域边界
			pDC->Rectangle(leftRect);
			pDC->Rectangle(rightRect);

			// 绘制窗口坐标系中的线段（左侧）
			CPoint p1= pMainFrame->x5_6p1;
			CPoint p2= pMainFrame->x5_6p2;
			DrawLineInWindow(pDC, leftRect, windowRect, p1, p2);

			// Cohen-Sutherland裁剪并绘制裁剪结果（右侧视区）
			CPoint clippedP1, clippedP2;
			if (CohenSutherlandClip(windowRect, p1, p2, clippedP1, clippedP2))
			{
				DrawLineInViewport(pDC, viewportRect, windowRect, clippedP1, clippedP2);
			}
			pDC->TextOut(leftRect.Width()/2, leftRect.top*4/5, CString("窗口"));
			pDC->TextOut(midX+rightRect.Width()/2, rightRect.top*4/5, CString("视区"));
			
			
			break;
			
		}
		case 63: 
		{
			pDC->TextOut(10 - centerX, centerY, CString("习题6-3: "));
			double a = 100.0;
			CPoint3D v[8] = {
			{-a / 2, -a / 2, -a / 2},
			{ a / 2, -a / 2, -a / 2},
			{ a / 2,  a / 2, -a / 2},
			{-a / 2,  a / 2, -a / 2},
			{-a / 2, -a / 2,  a / 2},
			{ a / 2, -a / 2,  a / 2},
			{ a / 2,  a / 2,  a / 2},
			{-a / 2,  a / 2,  a / 2}
			};
			// 绘制斜等测图（45度，比例0.5）
			DrawCube(pDC, v, 45, 0.5,CPoint(-300,0));

			// 绘制斜二测图（45度，比例1.0）
			DrawCube(pDC, v, 45, 1.0,CPoint(300,0));


			break;
		}		
		case 64: 
		{
			pDC->TextOut(10 - centerX, centerY, CString("习题6-4: "));
			pDC->MoveTo(0, rect.Height() / 2);
			pDC->LineTo(0,- rect.Height() / 2);			
			pDC->MoveTo(0,0);
			pDC->LineTo(rect.Width() /2,0);	
			pDC->MoveTo(rect.Width()/4,rect.Height()/2);
			pDC->LineTo(rect.Width()/4,-rect.Height()/2);
			
			// 定义长方体的8个底部顶点和尖顶位置
			double length = 180, width = 100, height = 80, roofHeight = 40;
			CPoint3D vertices[10] = {
				{-length / 2, 0, -width / 2},   // 底部 4 个顶点
				{ length / 2,  0 ,-width / 2,},
				{ length / 2,  0, width / 2},
				{-length / 2,  0, width / 2},
				{-length / 2,  height,-width / 2},  // 顶部 4 个顶点
				{ length / 2,  height,-width / 2},
				{ length / 2, height, width / 2},
				{-length / 2,  height, width / 2,},
				{-length / 2, height + roofHeight ,0},
				{length/2, height + roofHeight, 0}     // 尖顶两个
	
			};
			// 立体图绘制位置
			CPoint leftPosition(-rect.Width()/3, 0);

			// 三视图位置
			CPoint frontViewPosition(rect.Width()/2- rect.Width() / 8, rect.Height()/4);
			CPoint sideViewPosition(rect.Width() /4-rect.Width() / 8, -rect.Height() /4);
			CPoint topViewPosition(rect.Width() / 4 - rect.Width() / 8, rect.Height() / 4);

			// 绘制立体图（左侧）
			Draw3DObject(pDC, vertices, leftPosition, 45, 0.5);

			// 绘制三视图（右侧分区）
			DrawFrontView(pDC, vertices, frontViewPosition);
			DrawSideView(pDC, vertices, sideViewPosition);
			DrawTopView(pDC, vertices, topViewPosition);
			break;
		}
		case 83:
		{
			pDC->TextOut(10 - centerX, centerY, CString("习题8-3: "));
			exercises8_3(pDC);
			
			break;
		}
		case 85:
		{
			pDC->TextOut(10 - centerX, centerY, CString("习题8-5: "));
			exercises8_5(pDC);

			break;
		}
		case 71:
		{
			pDC->TextOut(10 - centerX, centerY, CString("习题7-1: "));
			exercises7_1(pDC);

			break;
		}
		case 72:
		{
			pDC->TextOut(10 - centerX, centerY, CString("习题7-2: "));
			exercises7_2(pDC);

			break;
		}
		case 73:
		{
			pDC->TextOut(10 - centerX, centerY, CString("习题7-3: "));
			exercises7_3(pDC);

			break;
		}
		default:
			break;
		}


	}
	
}

//3-4反走样斜线段
void CMFCGCView::wuLine(CDC* pDC,CPoint p0, CPoint p1)
{

	CPoint p, temp;
	int dx = p1.x - p0.x;
	int dy = p1.y - p0.y;
	double k = (dy * 1.00) / (dx * 1.00);//计算斜率

	if (dx == 0)//垂线
	{
		if (dy < 0)//起点在上方，调换
		{
			temp = p0;
			p0 = p1;
			p1 = temp;
		}
		for (p = p0; p.y < p1.y; p.y++)//主移动方向->y,不包括p1
		{
			pDC->SetPixelV(p.x, p.y, RGB(0, 0, 0));
		}
	}

	else
	{
		double e = 0.00;//增量

		if (k >= 0 && k <= 1)
		{
			if (dx < 0)//p1在左侧，调换
			{
				temp = p0;
				p0 = p1;
				p1 = temp;
			}//p0在左下

			for (p = p0; p.x < p1.x; p.x++)//主移动方向->x,不包括p1
			{
				pDC->SetPixelV(p.x, p.y, RGB(e * 255, e * 255, e * 255));
				pDC->SetPixelV(p.x, p.y + 1, RGB((1 - e) * 255, (1 - e) * 255, (1 - e) * 255));//不同亮度值
				e += k;

				if (e >= 1.0)
				{
					p.y++;
					e -= 1;
				}
			}
			/*p0.x+=10;
			p1.x+=10;
			pDC->MoveTo(p0);
			pDC->LineTo(p1);*/
		}
		else if (k > 1)
		{
			if (dy < 0)//p1在左侧，调换
			{
				temp = p0;
				p0 = p1;
				p1 = temp;
			}//p0在下方

			for (p = p0; p.y < p1.y; p.y++)//主移动方向->y,不包括p1
			{
				pDC->SetPixelV(p.x, p.y, RGB(e * 255, e * 255, e * 255));
				pDC->SetPixelV(p.x + 1, p.y, RGB((1 - e) * 255, (1 - e) * 255, (1 - e) * 255));
				e += 1.00 / (k * 1.00);

				if (e >= 1.0)
				{
					p.x++;
					e -= 1;
				}
			}
		}

		else if (k >= -1 && k < 0)
		{
			e = 0.00;
			if (dx < 0)//p1在左上，调换
			{
				temp = p0;
				p0 = p1;
				p1 = temp;
			}//p0在左上

			for (p = p0; p.x < p1.x; p.x++)//主移动方向->x,不包括p1
			{
				pDC->SetPixelV(p.x, p.y, RGB(-1 * e * 255, -1 * e * 255, -1 * e * 255));
				pDC->SetPixelV(p.x, p.y - 1, RGB((1 + e) * 255, (1 + e) * 255, (1 + e) * 255));//这里e是负数！！！
				e += k;

				if (e <= -1.0)
				{
					p.y--;
					e += 1.0;
				}
			}
		}

		else if (k < -1)
		{
			if (dy > 0)//p1在上方，调换
			{
				temp = p0;
				p0 = p1;
				p1 = temp;
			}//p0在上
			for (p = p0; p.y > p1.y; p.y--)//主移动方向->y,不包括p1
			{
				pDC->SetPixelV(p.x, p.y, RGB(e * 255, e * 255, e * 255));
				pDC->SetPixelV(p.x + 1, p.y, RGB((1 - e) * 255, (1 - e) * 255, (1 - e) * 255));
				e += -1.0 / (k * 1.0);

				if (e >= 1.0)
				{
					p.x++;
					e -= 1;
				}
			}
		}

	}

}
//3-8颜色渐变曲线


// CMFCGCView 打印

BOOL CMFCGCView::OnPreparePrinting(CPrintInfo* pInfo)
{
	// 默认准备
	return DoPreparePrinting(pInfo);
}

void CMFCGCView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: 添加额外的打印前进行的初始化过程
}

void CMFCGCView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: 添加打印后进行的清理过程
}


// CMFCGCView 诊断

#ifdef _DEBUG
void CMFCGCView::AssertValid() const
{
	CView::AssertValid();
}

void CMFCGCView::Dump(CDumpContext& dc) const
{
	CView::Dump(dc);
}

CMFCGCDoc* CMFCGCView::GetDocument() const // 非调试版本是内联的
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CMFCGCDoc)));
	return (CMFCGCDoc*)m_pDocument;
}
#endif //_DEBUG


// CMFCGCView 消息处理程序


void CMFCGCView::OnLButtonUp(UINT nFlags, CPoint point)
{
	// TODO:左键点击
	
// 获取指向主窗口的指针
	CMainFrame* pMainFrame = (CMainFrame*)AfxGetMainWnd();

	if (pMainFrame) // 确保指针有效
	{
		// 修改 CMainFrame 中的 nowDraw 变量
		switch (pMainFrame->nowDraw)
		{
		case 33:
		{// 获取点击的坐标
			//CString str;
			//str.Format(_T("右键点击坐标: X = %d, Y = %d"), point.x, point.y);

			//// 显示坐标信息
			//AfxMessageBox(str);

			lineList[LineNum][0] = point;//起始点赋值
			break;
			
		}
		default:
			break;
		} 
	
	}

	CView::OnLButtonUp(nFlags, point);
}


void CMFCGCView::OnRButtonUp(UINT nFlags, CPoint point)
{
	// TODO: 3-3右键点击事件
	// 获取指向主窗口的指针
	CMainFrame* pMainFrame = (CMainFrame*)AfxGetMainWnd();

	if (pMainFrame) // 确保指针有效
	{
		// 修改 CMainFrame 中的 nowDraw 变量
		switch (pMainFrame->nowDraw)
		{
		case 33:
		{
			lineList[LineNum][1] = point;//终止点赋值
			LineNum++;
			Invalidate();
			break;
	

		}
		default:
			break;
		}

	}
	CView::OnRButtonUp(nFlags, point);
	
}

// 在窗口中绘制未裁剪的线段
void CMFCGCView::DrawLineInWindow(CDC* pDC, const CRect& leftRect, const CRect& windowRect, CPoint p1, CPoint p2)
{
	int x1 = leftRect.left + (p1.x - windowRect.left) * leftRect.Width() / windowRect.Width();
	int y1 = leftRect.bottom - (p1.y - windowRect.top) * leftRect.Height() / windowRect.Height();
	int x2 = leftRect.left + (p2.x - windowRect.left) * leftRect.Width() / windowRect.Width();
	int y2 = leftRect.bottom - (p2.y - windowRect.top) * leftRect.Height() / windowRect.Height();

	pDC->MoveTo(x1, y1);
	pDC->LineTo(x2, y2);
}

// 在视区中绘制裁剪后的线段
void CMFCGCView::DrawLineInViewport(CDC* pDC, const CRect& viewportRect, const CRect& windowRect, CPoint p1, CPoint p2)
{
	int x1 = viewportRect.left + (p1.x - windowRect.left) * viewportRect.Width() / windowRect.Width();
	int y1 = viewportRect.bottom - (p1.y - windowRect.top) * viewportRect.Height() / windowRect.Height();
	int x2 = viewportRect.left + (p2.x - windowRect.left) * viewportRect.Width() / windowRect.Width();
	int y2 = viewportRect.bottom - (p2.y - windowRect.top) * viewportRect.Height() / windowRect.Height();

	pDC->MoveTo(x1, y1);
	pDC->LineTo(x2, y2);
}

// Cohen-Sutherland裁剪算法
bool CMFCGCView::CohenSutherlandClip(const CRect& rect, CPoint p1, CPoint p2, CPoint& clippedP1, CPoint& clippedP2)
{
	enum OutCode { INSIDE = 0, LEFT = 1, RIGHT = 2, BOTTOM = 4, TOP = 8 };

	auto ComputeOutCode = [&](CPoint p) {
		int code = INSIDE;
		if (p.x < rect.left) code |= LEFT;
		else if (p.x > rect.right) code |= RIGHT;
		if (p.y < rect.top) code |= BOTTOM;
		else if (p.y > rect.bottom) code |= TOP;
		return code;
		};

	int outcode1 = ComputeOutCode(p1);
	int outcode2 = ComputeOutCode(p2);

	bool accept = false;
	while (true) {
		if (!(outcode1 | outcode2)) { // 完全在视区内
			accept = true;
			break;
		}
		else if (outcode1 & outcode2) { // 完全在视区外
			break;
		}
		else {
			int outcodeOut = outcode1 ? outcode1 : outcode2;
			int x, y;

			if (outcodeOut & TOP) {
				x = p1.x + (p2.x - p1.x) * (rect.bottom - p1.y) / (p2.y - p1.y);
				y = rect.bottom;
			}
			else if (outcodeOut & BOTTOM) {
				x = p1.x + (p2.x - p1.x) * (rect.top - p1.y) / (p2.y - p1.y);
				y = rect.top;
			}
			else if (outcodeOut & RIGHT) {
				y = p1.y + (p2.y - p1.y) * (rect.right - p1.x) / (p2.x - p1.x);
				x = rect.right;
			}
			else if (outcodeOut & LEFT) {
				y = p1.y + (p2.y - p1.y) * (rect.left - p1.x) / (p2.x - p1.x);
				x = rect.left;
			}

			if (outcodeOut == outcode1) {
				p1 = { x, y };
				outcode1 = ComputeOutCode(p1);
			}
			else {
				p2 = { x, y };
				outcode2 = ComputeOutCode(p2);
			}
		}
	}

	if (accept) {
		clippedP1 = p1;
		clippedP2 = p2;
	}
	return accept;
}

void CMFCGCView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
	if (CMainFrame* pMainFrame = (CMainFrame*)AfxGetMainWnd())
	{
		if (pMainFrame->nowDraw != 71)return;
		int stp = 10; //设定步长
		switch (nChar)
		{
		case VK_UP:
			Phi -= stp;
			break;
		case VK_DOWN:
			Phi += stp;
			break;
		case VK_LEFT:
			Theta -= stp;
			break;
		case VK_RIGHT:
			Theta += stp;
			break;
		default:
			break;
		}
		Invalidate();

		CView::OnKeyDown(nChar, nRepCnt, nFlags);
	}
	
}
